using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Diagnostics;
using System.IO;
using WozLib.UI.Ink.SketchCommands;
using System.Xml.Serialization;
using System.Threading;
using System.Net;
using System.Windows.Controls;

namespace WozLib.Net
{
  public class WozClient
  {

    TcpClient _TcpClient;
    NetworkStream _NetworkStream;
    StreamReader _StreamReader;
    StreamWriter _StreamWriter;

    
    /// <summary>
    /// The HostName a WozClient last connected to.
    /// </summary>
    public static string HostName
    {
      get { return _HostName; }
    } public static string _HostName;


    public bool Connected
    {
      get
      {
        if (_TcpClient == null || !_TcpClient.Connected)
        {
          return false;
        }
        else
        {
          return true;
        }
      }
    }

    public WozClient()
    {
      try
      {
        _TcpClient = new TcpClient("localhost", WozServer.PORT);
        _HostName = "localhost";
      }
      catch
      {
        Debug.WriteLine("Cannot connect server");
        return;
      }

      _NetworkStream = _TcpClient.GetStream();
      _StreamReader = new StreamReader(_NetworkStream);
      _StreamWriter = new StreamWriter(_NetworkStream);
    }

    public WozClient(string addr)
    {
      try
      {
        _TcpClient = new TcpClient(addr, WozServer.PORT);
        _HostName = addr;
      }
      catch
      {
        Debug.WriteLine("Cannot connect server");
        return;
      }

      _NetworkStream = _TcpClient.GetStream();
      _StreamReader = new StreamReader(_NetworkStream);
      _StreamWriter = new StreamWriter(_NetworkStream);
    }

    public WozClient(string addr, int port, TextBox textBox)
    {
      try
      {
        _TcpClient = new TcpClient(new IPEndPoint(IPAddress.Parse(addr),port));
        _HostName = addr;
      }
      catch (Exception ex)
      {
        Debug.WriteLine("Cannot connect server");
        Debug.WriteLine(ex.ToString());
        textBox.Text += ex.ToString() + "\r\n";
        return;
      }

      _NetworkStream = _TcpClient.GetStream();
      _StreamReader = new StreamReader(_NetworkStream);
      _StreamWriter = new StreamWriter(_NetworkStream);
    }

    private Thread _ClientThread;

    public delegate void WozClientCommandsReceivedDelegate(SketchCommandCollection wozClientCommands);

    public event WozClientCommandsReceivedDelegate WozClientCommandsReceived;

    public bool SendWozClientCommands(SketchCommandCollection wozClientCommands)
    {
      if (this.Connected && wozClientCommands != null)
      {
        lock (_StreamWriter)
        {
          SketchCommandCollection toSerialize = wozClientCommands;

          // Insert code to set properties and fields of the object.
          //XmlSerializer mySerializer2 = new XmlSerializer(typeof());
          XmlSerializer mySerializer = new XmlSerializer(typeof(SketchCommandCollection));

          // To write to a file, create a StreamWriter object.
          StringWriter sw = new StringWriter();
          mySerializer.Serialize(sw, toSerialize);
          sw.Close();

          string toSend = sw.ToString();

          try
          {
            _StreamWriter.WriteLine(toSend.Length.ToString());
            _StreamWriter.Write(toSend);
            _StreamWriter.Flush();
          }
          catch (Exception ex)
          {
            Debug.WriteLine(ex.ToString());
            return false;
          }

          return true;
        }
      }
      else
      {
        return false;
      }
    }

    public void Start()
    {
      _ClientThread = new Thread(new ThreadStart(Run));
      _ClientThread.Start();
    }

    public void Stop()
    {
      // close down connection gracefully

      // then kill the thread
      _ClientThread.Abort();
    }

    private void Run()
    {
      if (_TcpClient != null && !(_TcpClient.Connected))
      {
        Debug.WriteLine("Client Server: cannot start because i'm not connected to the server");
      }
      else
      {
        while (true)
        {
          try
          {
            string strXmlLength = _StreamReader.ReadLine();
            //Debug.WriteLine("Incoming message \"{0}\"", strXmlLength);

            int xmlLength = int.Parse(strXmlLength);

            char[] xmlChars = new char[xmlLength];

            int lengthRead = _StreamReader.Read(xmlChars, 0, xmlLength);

            if (lengthRead != xmlLength)
            {
              //Debug.WriteLine("incorrect message length, expected " + xmlLength.ToString() + " but got " + lengthRead.ToString());

              while (lengthRead < xmlLength)
              {
                lengthRead += _StreamReader.Read(xmlChars, lengthRead, xmlLength - lengthRead);
              }
            }

            XmlSerializer mySerializer = new XmlSerializer(typeof(SketchCommandCollection));

            StringReader sr = new StringReader(new string(xmlChars));

            SketchCommandCollection unserialized = (SketchCommandCollection)mySerializer.Deserialize(sr);

            if (WozClientCommandsReceived != null)
            {
              WozClientCommandsReceived(unserialized);
            }
          }
          catch (Exception ex)
          {
            Debug.WriteLine("client closing because of an error: " + ex.ToString());
            return;
          }
        }
      }
    }
  }
}

